package com.balance.anole.client.retail.dialog;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.eclipse.core.databinding.observable.list.WritableList;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;

import com.balance.anole.business.to.ShopPaymentTO;
import com.balance.anole.client.common.service.CommonService;
import com.balance.anole.client.retail.payment.PaymentHelper;
import com.balance.anole.client.retail.payment.exception.InvalidPaymentException;
import com.balance.anole.client.retail.provider.ShopPaymentProvider;
import com.balance.anole.common.to.CodeLookTO;
import com.balance.anole.erp.component.CodeLookComboViewer;
import com.balance.anole.erp.security.SessionManager;
import com.balance.anole.erp.util.Messages;
import com.balance.anole.erp.util.NumberUtil;
import com.balance.anole.erp.util.SWTResourceManager;
import com.balance.anole.erp.util.ServicesCenter;
import com.balance.anole.utils.Constants;
import com.balance.anole.utils.DateUtil;

public class RetailAssemCloseDialog extends Dialog {

	final CommonService cs = ServicesCenter.getServicesCenter().getService(CommonService.class);

	private BigDecimal needPay;

	private Label label_totalPaidData;

	private Label label_totalChangeData;

	private String totalPaidValue;

	private String totalChangeValue = "0.00";

	private ShopPaymentTO selectShopPaymentTO;

	private boolean isReject;

	final WritableList wl = new WritableList(new ArrayList<ShopPaymentTO>(),ShopPaymentTO.class);

	public Set<ShopPaymentTO> getShopPaymentTOs() {
		return new HashSet<ShopPaymentTO>(wl);
	}

	public RetailAssemCloseDialog(Shell parentShell,String amount) {
		super(parentShell);

		BigDecimal value = new BigDecimal(amount);
		this.isReject = value.signum() < 0;
		this.needPay = value.abs();
	}

	protected void configureShell(Shell newShell) {
		super.configureShell(newShell);
		if(isReject){
			newShell.setText("组合退款");
		}else{
			newShell.setText("组合收款");
		}
	}

	protected void createButtonsForButtonBar(Composite parent) {
		// create OK and Cancel buttons by default
		createButton(parent, IDialogConstants.OK_ID, "确认",
				false);
		createButton(parent, IDialogConstants.CANCEL_ID,
				"取消", false);
	}

	protected Control createDialogArea(final Composite parent) {
		wl.clear();

		FormData formData = null;
		Composite container = (Composite)super.createDialogArea(parent);
		container.setLayout(new FormLayout());

		//---------------------------------------Left Part Start -------------------------------------------------
		TableViewer tableViewer = new TableViewer(container, SWT.BORDER|SWT.FULL_SELECTION);
		Table shopPaymentTable;
		shopPaymentTable = tableViewer.getTable();
		shopPaymentTable.setLinesVisible(true);
		shopPaymentTable.setHeaderVisible(true);
		formData = new FormData();
		formData.top = new FormAttachment(0,20);
		formData.bottom = new FormAttachment(65,-50);
		formData.left =  new FormAttachment(0,15);
		shopPaymentTable.setLayoutData(formData);
		String[] columnNames = new String[]{"支付方式","收款金额"};
		if(isReject){
			columnNames[1] = "退款金额";
		}

		int[] columnWidths = new int[]{100,120};
		int[] columnAlignments = new int[]{SWT.CENTER,SWT.CENTER};

		for(int i=0;i<columnNames.length;i++){
			TableColumn tableColumn = new TableColumn(shopPaymentTable,columnAlignments[i]);
			tableColumn.setText(columnNames[i]);
			tableColumn.setWidth(columnWidths[i]);
		}

		ObservableListContentProvider opContentProvider = new ObservableListContentProvider();
		tableViewer.setContentProvider(opContentProvider);
		tableViewer.setLabelProvider(new ShopPaymentProvider());
		tableViewer.setInput(wl);

		Label label_paymentMode = new Label(container,SWT.RIGHT);
		label_paymentMode.setText("支付方式:");
		formData = new FormData();
		formData.left = new FormAttachment(0,15);
		formData.top = new FormAttachment(shopPaymentTable,15);
		label_paymentMode.setLayoutData(formData);

		final ComboViewer comboViewer_paymentMode = new CodeLookComboViewer(Constants.CODE_TYPE_PAYMENT_TYPE, container,SWT.BORDER|SWT.READ_ONLY, true);
		comboViewer_paymentMode.setSelection(new StructuredSelection(new CodeLookTO(Constants.CODE_TYPE_PAYMENT_TYPE, "B")));

		formData = new FormData();
		formData.left = new FormAttachment(label_paymentMode,5);
		formData.top = new FormAttachment(shopPaymentTable,15);
		comboViewer_paymentMode.getCombo().setLayoutData(formData);

		Label label_partToPay = new Label(container,SWT.RIGHT);

		if(isReject){
			label_partToPay.setText("退款金额:");
		}else{
			label_partToPay.setText("收款金额:");
		}
		formData = new FormData();
		formData.left = new FormAttachment(0,15);
		formData.top = new FormAttachment(label_paymentMode,15);
		label_partToPay.setLayoutData(formData);

		final Text text_partToPay = new Text(container,SWT.BORDER);
		formData = new FormData();
		formData.left = new FormAttachment(label_partToPay,5);
		formData.top = new FormAttachment(label_paymentMode,15);
		text_partToPay.setLayoutData(formData);
		//---------------------------------------Left Part End -------------------------------------------------

		//---------------------------------------Right Part Start -------------------------------------------------

		Group group = new Group(container, SWT.NULL);

		if(isReject){
			group.setText("退款信息");
		}else{
			group.setText("收银信息");
		}
		formData = new FormData();
		formData.left = new FormAttachment(shopPaymentTable,20);
		formData.top = new FormAttachment(0,15);
		formData.bottom = new FormAttachment(100,-125);
		formData.right = new FormAttachment(100,-15);
		group.setLayoutData(formData);
		group.setLayout(new FormLayout());

		final Label label_totalToPay = new Label(group,SWT.RIGHT);

		if(isReject){
			label_totalToPay.setText("应退总金额:");
		}else{
			label_totalToPay.setText("应付总金额:");
		}
		formData = new FormData();
		formData.left = new FormAttachment(0,20);
		formData.right = new FormAttachment(100,-25);
		formData.top = new FormAttachment(0,20);
		label_totalToPay.setLayoutData(formData);

		final Label label_totalToPayData = new Label(group,SWT.RIGHT);
		label_totalToPayData.setText(NumberUtil.formatMoney(needPay));
		label_totalToPayData.setFont(SWTResourceManager.getFont("", 12, SWT.BOLD));
		formData = new FormData();
		formData.left = new FormAttachment(0,20);
		formData.top = new FormAttachment(label_totalToPay,20);
		formData.right = new FormAttachment(100,-5);
		label_totalToPayData.setLayoutData(formData);

		final Label label_totalPaid = new Label(group,SWT.RIGHT);

		if(isReject){
			label_totalPaid.setText("已退总金额:");
		}else{
			label_totalPaid.setText("已收总金额:");
		}
		formData = new FormData();
		formData.left = new FormAttachment(0,20);
		formData.top = new FormAttachment(label_totalToPayData,20);
		label_totalPaid.setLayoutData(formData);

		label_totalPaidData = new Label(group,SWT.RIGHT);
		label_totalPaidData.setText("0.00");
		label_totalPaidData.setFont(SWTResourceManager.getFont("", 12, SWT.BOLD));
		formData = new FormData();
		formData.left = new FormAttachment(0,20);
		formData.top = new FormAttachment(label_totalPaid,20);
		formData.right = new FormAttachment(100,-5);
		label_totalPaidData.setLayoutData(formData);

		final Label label_totalChange = new Label(group,SWT.RIGHT);
		if(isReject){
			label_totalChange.setText("退款差额:");
		}else{
			label_totalChange.setText("找零金额:");
		}

		formData = new FormData();
		formData.left = new FormAttachment(0,20);
		formData.top = new FormAttachment(label_totalPaidData,20);
		label_totalChange.setLayoutData(formData);

		label_totalChangeData = new Label(group,SWT.RIGHT);
		label_totalChangeData.setText("0.00");
		label_totalChangeData.setFont(SWTResourceManager.getFont("", 12, SWT.BOLD));
		formData = new FormData();
		formData.left = new FormAttachment(0,20);
		formData.top = new FormAttachment(label_totalChange,20);
		formData.right = new FormAttachment(100,-5);
		formData.bottom = new FormAttachment(100,-25);
		label_totalChangeData.setLayoutData(formData);
		//---------------------------------------Right Part End -------------------------------------------------


		text_partToPay.addVerifyListener(new VerifyListener() {
			public void verifyText(VerifyEvent e) {
				String money = text_partToPay.getText().substring(0, e.start) + e.text + text_partToPay.getText().substring(e.end);
				if(StringUtils.isEmpty(money)){
					e.doit = true;
				}else if (NumberUtil.isValidMoney(money)){
					e.doit = true;
				}else{
					e.doit = false;
				}
			}
		});

		text_partToPay.addKeyListener(new KeyListener(){
			@Override
			public void keyPressed(KeyEvent e) {

			}
			@SuppressWarnings("unchecked")
			@Override
			public void keyReleased(KeyEvent e) {
				if(e.keyCode == 13){
					String paidValueStr = text_partToPay.getText();
					if(StringUtils.isEmpty(paidValueStr)){
						//pay bill.
						okPressed();
					}else{
						BigDecimal totalPaidValue = new BigDecimal(label_totalPaidData.getText());

						CodeLookTO paymentMode = (CodeLookTO)((StructuredSelection)comboViewer_paymentMode.getSelection()).getFirstElement();
						if(paymentMode !=null){
							BigDecimal paidValue = new BigDecimal(paidValueStr);

							ShopPaymentTO shopPaymentTO = new ShopPaymentTO();
							shopPaymentTO.setPaidValue(paidValue);
							shopPaymentTO.setPaymentMode(paymentMode);

							ShopPaymentTO existShopPayment = checkExistShopPaymentTO(wl, paymentMode);
							if(existShopPayment != null){
								wl.remove(existShopPayment);
								shopPaymentTO.setPaidValue(existShopPayment.getPaidValue().add(paidValue));
							}

							shopPaymentTO.setCreateDt(DateUtil.getSystemCurrentDate());
							shopPaymentTO.setCreateBy(SessionManager.getInstance().getLoginUser().getStaffInfo());
							wl.add(shopPaymentTO);

							BigDecimal changPaidValue = BigDecimal.ZERO;
							try {
								changPaidValue = PaymentHelper.checkPaidValueAndGetChain(needPay, (ArrayList<ShopPaymentTO>)new ArrayList<ShopPaymentTO>(wl).clone());
							} catch (InvalidPaymentException ex){
								MessageDialog.openError(getShell(), Messages.DIALOG_INFO_ERROR, ex.getMessage());
								//change the payment list back.
								wl.remove(shopPaymentTO);
								if(existShopPayment != null){
									wl.add(existShopPayment);
								}
								return;
							}


							totalPaidValue = totalPaidValue.add(paidValue);
//							BigDecimal changPaidValue = totalPaidValue.subtract(needPay);

							label_totalPaidData.setText(NumberUtil.formatMoney(totalPaidValue));
							label_totalChangeData.setText(NumberUtil.formatMoney(changPaidValue));

							text_partToPay.setText("");
						}else{
							MessageDialog.openError(getShell(), Messages.DIALOG_INFO_ERROR, "未选择付款方式！");
							comboViewer_paymentMode.getCombo().forceFocus();
						}
					}
				}
			}
		});


		final MenuManager menuManager = new MenuManager();
		final Menu menu = menuManager.createContextMenu(shopPaymentTable);

		final Action clearAction = new Action("清除") {
			public void run(){
				if(selectShopPaymentTO != null){
					wl.remove(selectShopPaymentTO);
					formatPaidValue(wl,label_totalPaidData,label_totalChangeData);
					setEnabled(false);
				}
			}
		};
		clearAction.setId("retail.assem.item.clear");
		clearAction.setEnabled(false);
		menuManager.add(clearAction);

		menuManager.add(new Action("全部清除") {
			@Override
			public void run(){
				if(wl == null || wl.size() == 0){
					MessageDialog.openError(parent.getShell(), Messages.DIALOG_INFO_ERROR, "没有选项需要清除！");
				}else{
					text_partToPay.setText("");
					label_totalPaidData.setText("0.00");
					label_totalChangeData.setText("0.00");

					wl.clear();
				}
			}
		});

		shopPaymentTable.setMenu(menu);

		tableViewer.getTable().addSelectionListener(new SelectionListener(){

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
				((ActionContributionItem)menuManager.find("retail.assem.item.clear")).getAction().setEnabled(true);
			}

			@Override
			public void widgetSelected(SelectionEvent e) {
				((ActionContributionItem)menuManager.find("retail.assem.item.clear")).getAction().setEnabled(true);
			}

		});

		tableViewer.addSelectionChangedListener(new ISelectionChangedListener(){

			@Override
			public void selectionChanged(SelectionChangedEvent event) {
				StructuredSelection selection = (StructuredSelection)event.getSelection();
				Object element = selection.getFirstElement();
				if(element != null){
					selectShopPaymentTO = (ShopPaymentTO)element;
				}
			}
		});

		//default to focus in the money input box.
		text_partToPay.forceFocus();
		text_partToPay.selectAll();

		return parent;
	}

	private ShopPaymentTO checkExistShopPaymentTO(List<ShopPaymentTO> listOfShopPayment,CodeLookTO paymentMode){
		if(listOfShopPayment != null){
			for(Iterator<ShopPaymentTO> it = listOfShopPayment.iterator(); it.hasNext();){
				ShopPaymentTO t = (ShopPaymentTO)it.next();
				if(t.getPaymentMode().getId().equals(paymentMode.getId())){
					return t;
				}
			}
		}
		return null;
	}

	protected void okPressed(){
		if(label_totalPaidData == null || label_totalPaidData.getText() == null || "".equals(label_totalPaidData.getText()) || (Double.parseDouble(label_totalPaidData.getText()) < needPay.doubleValue())){
			MessageDialog.openError(getShell(), Messages.DIALOG_INFO_ERROR, "付款不足！");
		}else{
			totalPaidValue = label_totalPaidData.getText();
			totalChangeValue = label_totalChangeData.getText();
			super.okPressed();
		}
	}

	private void formatPaidValue(List<ShopPaymentTO> listOfShopPayment,
								Label label_totalPaidData,
								Label label_totalChangeData){
		if(listOfShopPayment.size()==0){
			label_totalPaidData.setText("0.00");
			label_totalChangeData.setText("0.00");
		}else{
			BigDecimal m = BigDecimal.ZERO;

			for(Iterator<ShopPaymentTO> it = listOfShopPayment.iterator(); it.hasNext();){
				ShopPaymentTO t = (ShopPaymentTO)it.next();
				BigDecimal s_m = t.getPaidValue();
				m = m.add(s_m);
			}

			label_totalPaidData.setText(NumberUtil.formatMoney(m));

			BigDecimal m_d = m.subtract(needPay);
			label_totalChangeData.setText(NumberUtil.formatMoney(m_d));
		}
	}


	public String getTotalPaidValue() {
		return totalPaidValue;
	}

	public void setTotalPaidValue(String totalPaidValue) {
		this.totalPaidValue = totalPaidValue;
	}

	public String getTotalChangeValue() {
		return totalChangeValue;
	}

	public void setTotalChangeValue(String totalChangeValue) {
		this.totalChangeValue = totalChangeValue;
	}
}
